#include "inorder/cache.h"
namespace config
{
    const Value<uint64_t> normal_cache_read_latency = {"normal_cache_read_latency", 4, "normal cache read latency"};
    const Value<uint64_t> normal_cache_write_latency = {"normal_cache_write_latency", 6, "normal cache write latency"};
    const Value<uint64_t> normal_cache_outstanding_num = {"normal_cache_outstanding_num", 8, "normal cache outstanding num"};
} // namespace config

NormalNaiveCache::NormalNaiveCache()
{
    reset();
}
NormalNaiveCache::~NormalNaiveCache()
{
}
void NormalNaiveCache::reset()
{
    cycle = 0;
    mshrs.clear();
}
bool NormalNaiveCache::send(OP *op)
{
    if (mshrs.size() >= config::normal_cache_outstanding_num)
        return false;
    mshrs.push_back(std::make_tuple(op, cycle));
    return true;
}
bool NormalNaiveCache::recv(OP *op)
{
    auto it = std::find_if(mshrs.begin(), mshrs.end(), [op](MSHR &mshr)
                           { return op->id == std::get<0>(mshr)->id; });

    if (it == mshrs.end())
    {
        std::cerr << "[Error] Could not find op:" << std::to_string(op->id) << std::endl;
        return false;
    }

    auto mop = std::get<0>(*it);
    auto mcycle = std::get<1>(*it);

    switch (mop->trace.opcode)
    {
    case OP_LD:
        if (mcycle + config::normal_cache_read_latency >= cycle)
        {
            return false;
        }
        else
        {
            mshrs.erase(it);
            return true;
        }
        break;
    case OP_ST:
        if (mcycle + config::normal_cache_write_latency >= cycle)
        {
            return false;
        }
        else
        {
            mshrs.erase(it);
            return true;
        }
        break;

    default:
        std::cerr << "[Error] Should not send non-memory op to memory!" << std::to_string(op->id) << std::endl;
        return false;
        break;
    }
}
void NormalNaiveCache::run()
{
    cycle++;
}
